package com.xdf.whiteaccount.service.impl;

import com.xdf.whiteaccount.dao.*;
import com.xdf.whiteaccount.entity.*;
import com.xdf.whiteaccount.service.ConfigSQLBalanceService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Year;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

@Service
public class ConfigSQLBalanceServiceImpl implements ConfigSQLBalanceService {
    //    private static final Logger logger = Logger.getLogger(ConfigSQLBalanceServiceImpl.class);
//    @Autowired
//    private CarryoutService carryoutService;
    @Autowired
    private JrkbillsumMapper jrkbillsumMapper;
    @Autowired
    private CallMapper callMapper;
    @Autowired
    private WhitebillfhMapper whitebillfhMapper;
    @Autowired
    private ReceivablesMapper receivablesMapper;
    @Autowired
    private MaterialOrderMapper materialOrderMapper;
    @Autowired
    private SqlMapper sqlMapper;
    @Autowired
    private MaterialAccountPayableMapper materialAccountPayableMapper;
    @Autowired
    private PlanMapper planMapper;
    @Autowired
    private SupplierMapper supplierMapper;
    @Autowired
    private ContactCompanyMapper contactCompanyMapper;

    public String host = "localhost";
    public String root = "root";
    public String pwd = "chanchaw";
    public String dbName = "white_account_001";
    public String jdbcUrl;


    /**
     * 查询结转仓库的余额
     *
     * @return
     */
    @Override
    public CarryForward balanceForwary() throws Exception {
        CarryForward carryForward = new CarryForward();
        Date start = getStart();
        /*应收账款*/
        List<Map<String, Object>> paymentList = callMapper.getAllReceivablesDetail(new Date());
        ArrayList<Receivables> receivablesMent = getReceivablesList(paymentList);
        /*应付账款*/
        List<Map<String, Object>> allAccountPayable = callMapper.getAllAccountPayable(new Date());
        ArrayList<MaterialAccountPayable> receivablesAble = getMaterialAccountPayableList(allAccountPayable);
        /*原料库存*/
        List<Map<String, Object>> allMaterialStorage = callMapper.getAllMaterialStorage();
        ArrayList<MaterialOrder> materialOrders = getMaterialOrder(allMaterialStorage);
        /*白坯库存*/
        List<Map<String, Object>> greyfabricStorage = callMapper.getGreyfabricStorage(0, new Date());
        /*放入结转对象*/
        carryForward.setReceivablesMent(receivablesMent);
        carryForward.setReceivablesAble(receivablesAble);
        carryForward.setMaterialOrders(materialOrders);
        carryForward.setGreyfabricStorage(greyfabricStorage);
        return carryForward;
    }

    //获取今年第一天
    private Date getStart() {
        String startStr = Year.now().getValue() + "-01-01";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date start = new Date();
        try {
            start = formatter.parse(startStr); // 使用parse方法将字符串转换成Date对象
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return start;
    }

    /**
     * 备份数据库
     *
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public ResponseResult<Void> backups() throws IOException, InterruptedException {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        DatabaseSetting databaseSetting = new DatabaseSetting();
        databaseSetting.setHost(host);
        databaseSetting.setRoot(root);
        databaseSetting.setPwd(pwd);
        databaseSetting.setDbName(dbName);
        databaseSetting.setBackupPath("D:\\结转数据库备份\\");
        databaseSetting.setBackupName("backup(" + sdf.format(date) + "111).sql");
        databaseSetting.setRestoreName(dbName);

        // mysqldump命令
        ProcessBuilder processBuilder = new ProcessBuilder(
                "C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin\\mysqldump",
                "-u", databaseSetting.getRoot(),
                "-p" + databaseSetting.getPwd(),
                databaseSetting.getDbName(),
                "whitebillfh",
                "cp_billfh",
                "dye_fabric_inbound",
                "product_outward_order",
                "receivables",
                "material_account_payable",
                "material_order",
                "jrkbillsum",
                "jrkbill_adjust"
        );
        // 重定向输出到备份文件
        processBuilder.redirectOutput(new File(databaseSetting.getBackupPath() + databaseSetting.getBackupName()));
        processBuilder.redirectErrorStream(true); // 合并错误流和输出流

        try {
            Process process = processBuilder.start();

            // 读取输出流
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line); // 打印输出，以便调试
                }
            }

            int exitCode = process.waitFor(); // 等待进程完成
            if (exitCode != 0) {
                throw new RuntimeException("备份失败，错误代码: " + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException("备份过程中出现异常: " + e.getMessage(), e);
        }
        ResponseResult<Void> result = new ResponseResult<>();
        result.setSuccess(true);
        result.setMessage("成功");
        return result;
    }

    /**
     * 恢复数据库
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public ResponseResult<Void> recover() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        DatabaseSetting databaseSetting = new DatabaseSetting();
        databaseSetting.setHost(host);
        databaseSetting.setRoot(root);
        databaseSetting.setPwd(pwd);
        databaseSetting.setDbName(dbName);
        databaseSetting.setBackupPath("D:\\结转数据库备份\\");
        databaseSetting.setBackupName("backup(" + sdf.format(date) + "111).sql");
        databaseSetting.setRestoreName(dbName);

        String filePath = databaseSetting.getBackupPath() + databaseSetting.getBackupName();
        Path path = Paths.get(filePath);

        if (Files.exists(path)) {
            // mysql命令
            ProcessBuilder processBuilder = new ProcessBuilder(
                    "C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin\\mysql",
                    databaseSetting.getDbName()
            );

            // 启动MySQL进程
            try {
                Process process = processBuilder.start();
                // 获取输出流并写入过滤后的内容
                try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8));
                     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = br.readLine()) != null) {
                        // 检查是否包含警告信息
                        if (line.contains("mysqldump: [Warning] Using a password on the command line interface can be insecure.")) {
                            continue; // 跳过这一行
                        }
                        writer.write(line);
                        writer.newLine();
                    }
                    writer.flush();
                }

                // 关闭输出流
                process.getOutputStream().close();

                // 捕获输出流
                StringBuilder output = new StringBuilder();
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        output.append(line).append("\n");
                        System.out.println(line);
                    }
                }

                int exitCode = process.waitFor();
                if (exitCode != 0) {
                    throw new RuntimeException("恢复失败！错误信息: " + output.toString());
                }
            } catch (IOException | InterruptedException e) {
                throw new RuntimeException("恢复过程中出现异常: " + e.getMessage(), e);
            }
        } else {
            throw new RuntimeException("备份文件不存在！");
        }
        ResponseResult<Void> result = new ResponseResult<>();
        result.setSuccess(true);
        result.setMessage("成功");
        return result;
    }

    /**
     * 结转数据库
     *
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public ResponseResult<Void> backupsAndbalance() throws Exception {
        //备份数据
        ResponseResult<Void> backups = backups();
        if (backups.isSuccess()) {
            CarryForward carryForward = balanceForwary();
            //结转应收款
            ArrayList<Receivables> receivablesMent = carryForward.getReceivablesMent();
            sqlMapper.deleteMent();//清空应收款
            receivablesMapper.multiInsert(receivablesMent);//写入应收款表
            //结转应付款
            List<Map<String, Object>> allAccountPayable = callMapper.getAllAccountPayable(new Date());
            ArrayList<MaterialAccountPayable> receivablesAble = getMaterialAccountPayableList(allAccountPayable);
//            ArrayList<MaterialAccountPayable> receivablesAble = carryForward.getReceivablesAble();
            sqlMapper.deleteAble();//清空应付款
            materialAccountPayableMapper.multiInsert(receivablesAble);//写入应付款表
            //结转原料库存
            ArrayList<MaterialOrder> materialOrders = carryForward.getMaterialOrders();
            sqlMapper.deleteOrders();//清空原料
            materialOrderMapper.multiInsert(materialOrders);//写入原料库存
            //结转白坯库存
            List<Map<String, Object>> greyfabricStorage = carryForward.getGreyfabricStorage();
            ArrayList<Jrkbillsum> jrkbillsumList = getJrkbillsum(greyfabricStorage);
            sqlMapper.deleteStorage();//清空白坯
            jrkbillsumMapper.multiInsert(jrkbillsumList);//写入白坯库存

            //将结转的原料部分（重复部分）去除
//            List<Map<String, Object>> allMaterialStorage = callMapper.getAllMaterialStorage();
//            ArrayList<MaterialOrder> orderList = getMaterialOrder(allMaterialStorage);
//            List<MaterialAccountPayable> materialAccountPayables = mergeAndCalculateMoney(receivablesAble, orderList);
//            int i = materialAccountPayableMapper.multiUpdate(materialAccountPayables);
//            if (i < 0) throw new RuntimeException("在计算应收款结余部分时出错，结转失败！");
        }else {
            throw new RuntimeException("没有检测到备份文件，请先备份后再结转！");
        }
        ResponseResult<Void> result = new ResponseResult<>();
        result.setSuccess(true);
        result.setMessage("成功");
        return result;
    }

    /*//计算不含原料的应付款
    private List<MaterialAccountPayable> mergeAndCalculateMoney(List<MaterialAccountPayable> payableList, List<MaterialOrder> orderList) {
        for (MaterialOrder materialOrder : orderList) {
            String supplierId = materialOrder.getSupplierId();
            Supplier supplier = supplierMapper.selectByPrimaryKey(supplierId);
            materialOrder.setSupplierName(supplier.getSupplierName());
        }
        Map<String, BigDecimal> totalMoneyMap = orderList.stream()
                .collect(Collectors.groupingBy(
                        MaterialOrder::getSupplierName, // 根据name字段分组
                        Collectors.reducing(BigDecimal.ZERO, MaterialOrder :: getInputMoney, BigDecimal::add) // 对每组中的money字段求和
                ));
        Map<String, BigDecimal> moneyMap = payableList.stream()
                .collect(Collectors.toMap(
                        MaterialAccountPayable::getClientName,
                        MaterialAccountPayable::getMoney
                ));
        // 更新moneyMap中的数据
        totalMoneyMap.forEach(new BiConsumer<String, BigDecimal>() {
            @Override
            public void accept(String supplierName, BigDecimal money) {
                if (totalMoneyMap.containsKey(supplierName)) {
                    // 如果name已存在，则进行运算
//                    if (moneyMap.get(supplierName).compareTo(BigDecimal.ZERO) < 0) moneyMap.put(supplierName, moneyMap.get(supplierName).subtract(money.negate()));
//                    if (moneyMap.get(supplierName).compareTo(BigDecimal.ZERO) > 0) moneyMap.put(supplierName, moneyMap.get(supplierName).subtract(money));
                    BigDecimal decimal = moneyMap.get(supplierName).add(money);
                    moneyMap.put(supplierName, decimal);
                } else {
                    // 如果name不存在，则直接添加到moneyMap中
                    moneyMap.put(supplierName, money.add(money));
                }
            }
        });
        // 将moneyMap中的数据转换回列表
        ArrayList<MaterialAccountPayable> list = new ArrayList<>(payableList);
        moneyMap.forEach(new BiConsumer<String, BigDecimal>() {
            @Override
            public void accept(String s, BigDecimal newMoney) {
                list.stream()
                        .filter(materialAccountPayable -> materialAccountPayable.getClientName().equals(s))
                        .forEach(materialAccountPayable -> materialAccountPayable.setMoney(newMoney.setScale(2, RoundingMode.HALF_UP)));
            }
        });
        return list;
    }*/

    //转换为白坯对象
    private ArrayList<Jrkbillsum> getJrkbillsum(List<Map<String, Object>> greyfabricStorage) {
        ArrayList<Jrkbillsum> list = new ArrayList<>();
        for (Map<String, Object> map : greyfabricStorage) {
            int ps = Integer.parseInt(String.valueOf(map.get("ps")));
            if (ps != 0){
                Jrkbillsum jrkbillsum = new Jrkbillsum();
                Plan plan = planMapper.selectByPlanCode(String.valueOf(map.get("planCode")));
                if (plan == null) throw new RuntimeException("查询计划失败！");
                ContactCompany contactCompany = contactCompanyMapper.selectByPrimaryKey(plan.getContactCompanyId());
                if (contactCompany == null) {
                    plan.setContactCompanyId("000");
                    planMapper.updateByPrimaryKey(plan);
                }
                jrkbillsum.setPlanid(Integer.parseInt(String.valueOf(plan.getId())));
                jrkbillsum.setPs(ps);
                double qty = Double.parseDouble(String.valueOf(map.get("qty")));
                jrkbillsum.setQty(BigDecimal.valueOf(qty).setScale(1, RoundingMode.HALF_UP));
                jrkbillsum.setCreatedate(new Date());
                list.add(jrkbillsum);
            }
        }
        return list;
    }

    //转换为原料对象
    private ArrayList<MaterialOrder> getMaterialOrder(List<Map<String, Object>> allMaterialStorage) {
        ArrayList<MaterialOrder> list = new ArrayList<>();
        for (Map<String, Object> map : allMaterialStorage) {
            MaterialOrder materialOrder = new MaterialOrder();
            String str = String.valueOf(map.get("id"));
            long id = Long.parseLong(str);
            MaterialOrder order = materialOrderMapper.selectByPrimaryKey(id);
            BeanUtils.copyProperties(order, materialOrder);
            materialOrder.setId(null);
            double inputKilo = Double.parseDouble(String.valueOf(map.get("input_kilo")));
            materialOrder.setInputKilo(BigDecimal.valueOf(inputKilo).setScale(1, RoundingMode.HALF_UP));
            double boxAmount = Double.parseDouble(String.valueOf(map.get("box_amount")));
            materialOrder.setBoxAmount(BigDecimal.valueOf(boxAmount).setScale(1, RoundingMode.HALF_UP));
            materialOrder.setPrice(new BigDecimal("0"));
            materialOrder.setInputMoney(new BigDecimal("0"));
            materialOrder.setSupplierName(String.valueOf(map.get("supplier_name")));
            if (materialOrder.getBoxAmount().compareTo(new BigDecimal("0")) != 0 || materialOrder.getInputAmount().compareTo(new BigDecimal("0")) != 0) list.add(materialOrder);
        }
        return list;
    }

    //计算应收款
    private ArrayList<Receivables> getReceivablesList(List<Map<String, Object>> paymentList) {
        ArrayList<Receivables> list = new ArrayList<>();
        Map<String, BigDecimal> collect = paymentList.stream()
                .collect(
                        Collectors.groupingBy(
                                m -> String.valueOf(m.get("client")), // 分组键：客户端字符串
                                Collectors.mapping(
                                        m -> {
                                            Object money = m.get("money");
                                            if (money instanceof BigDecimal) {
                                                return (BigDecimal) money;
                                            } else if (money instanceof String) {
                                                try {
                                                    return new BigDecimal((String) money);
                                                } catch (NumberFormatException e) {
                                                    // 处理无效的数值字符串
                                                    return BigDecimal.ZERO;
                                                }
                                            } else if (money instanceof Number) {
                                                return new BigDecimal(((Number) money).doubleValue());
                                            } else {
                                                // 处理未知类型或null值
                                                return BigDecimal.ZERO;
                                            }
                                        },
                                        Collectors.reducing(BigDecimal.ZERO, BigDecimal::add) // 求和
                                )
                        )
                );
        collect.forEach(new BiConsumer<String, BigDecimal>() {
            @Override
            public void accept(String client, BigDecimal money) {
                if (money.compareTo(new BigDecimal("0")) != 0) {
                    Receivables receivables = new Receivables();
                    receivables.setClient(client);
                    receivables.setMoney(money.setScale(2, RoundingMode.HALF_UP).negate());
                    receivables.setBilltype("结转数据");
                    receivables.setBillmemo("结转数据");
                    receivables.setUpload(0);
                    receivables.setBilldate(new Date());
                    list.add(receivables);
                }
            }
        });
        return list;
    }

    //计算应付款
    private ArrayList<MaterialAccountPayable> getMaterialAccountPayableList(List<Map<String, Object>> paymentList) {
        ArrayList<MaterialAccountPayable> list = new ArrayList<>();
        Map<String, BigDecimal> collect = paymentList.stream()
                .collect(Collectors.groupingBy(
                        m -> m.get("supplier_name").toString(),
                        Collectors.mapping(
                                m -> new BigDecimal(m.get("money").toString()),
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)// 求和
                        )
                ));
        collect.forEach(new BiConsumer<String, BigDecimal>() {
            @Override
            public void accept(String client, BigDecimal money) {
                if (money.compareTo(new BigDecimal("0")) != 0) {
                    MaterialAccountPayable materialAccountPayable = new MaterialAccountPayable();
                    materialAccountPayable.setClientName(client);
                    materialAccountPayable.setBillDate(new Date());
                    materialAccountPayable.setMoney(money.setScale(2, RoundingMode.HALF_UP).negate());
                    materialAccountPayable.setBilltype("结转数据");
                    materialAccountPayable.setBillmemo("结转数据");
                    materialAccountPayable.setUpload(0);
                    materialAccountPayable.setIsPush(false);
                    list.add(materialAccountPayable);
                }
            }
        });
        return list;
    }
}
